package org.activequant.data.util.converter;

import java.util.Iterator;

import org.activequant.core.domainmodel.SeriesSpecification;
import org.activequant.core.domainmodel.data.MarketDataEntity;
import org.activequant.data.retrieval.ISeriesDataIteratorSource;

/**
 * Abstract data transforming iterator source decorator.
 * Wraps another iterator source and performs transformation of each
 * data item.<br/>
 * An abstract class. TransformingIteratorSourceDecorator&lt;T extends MarketDataEntity&lt;T&gt;&gt; implements ISeriesDataIteratorSource&lt;T&gt;. Holds the following associated variables:
 * <ul>
 * <li>source(ISeriesDataIteratorSource&lt;T&gt;)</li>
 * <li>timeDelay(long)</li>
 * </ul>
 * @author Mike Kroutikov.
 *
 * @param <T> market data entity type.
 */
public abstract class TransformingIteratorSourceDecorator<T extends MarketDataEntity<T>>  implements ISeriesDataIteratorSource<T> {
	/**
	 * private final ISeriesDataIteratorSource&lt;T&gt; source;
	 */
	private final ISeriesDataIteratorSource<T> source;
	/**
	 * private long timeDelay = 0;
	 */
	private long timeDelay = 0;
	/**
	 * An abstract method
	 * @param in
	 * @return
	 */
	protected abstract T transform(T in);
	/**
	 * constructs a TransformingIteratorSourceDecorator&lt;T extends MarketDataEntity&lt;T&gt;&gt; (implements ISeriesDataIteratorSource&lt;T&gt;) using the given
	 * source(ISeriesDataIteratorSource&lt;T&gt;) to set its associated source(ISeriesDataIteratorSource&lt;T&gt;)
	 * @param source
	 */
	public TransformingIteratorSourceDecorator(ISeriesDataIteratorSource<T> source) {
		this.source = source;
	}
	/**
	 * sets the associated timeDelay(long) with the given val(long)
	 * @param val
	 */
	public void setTimeDelayNanos(long val) {
		timeDelay = val;
	}
	/**
	 * returns the associated timeDelay(long)
	 * @return
	 */
	public long getTimeDelayNanos() {
		return timeDelay;
	}
	
	
	/**
	 * <strong>1.</strong> Fetches a fetched(Iterable&lt;T&gt;) for the given seriesSpecification(SeriesSpecification) from the associated source(ISeriesDataIteratorSource&lt;T&gt;).<br/>
	 * <strong>2.</strong> returns an Iterable&lt;T&gt; wrapper for that fetched(Iterable&lt;T&gt;) which transforms each next element using the abstract <code>T transform(T in)</code> method
	 */
	public Iterable<T> fetch(SeriesSpecification seriesSpecification) throws Exception {
		final Iterable<T> fetched = source.fetch(seriesSpecification);
		
		return new Iterable<T>() {
			public Iterator<T> iterator() {
				final Iterator<T> iterator = fetched.iterator();
				return new Iterator<T>() {

					public boolean hasNext() {
						return iterator.hasNext();
					}

					public T next() {
						T out = iterator.next();
						return transform(out);
					}

					public void remove() {
						iterator.remove();
					}
				};
			}
		};
	}
}
